﻿/* 
 *  <copyright file="WorldMapSpawner.cs" company="Wesley Jowitt">
 *  
 *  SobrietyEngine: Copyright (c) 2011 Wesley Jowitt
 *  
 *  This software is distributed under a software license.
 *   * As of the creation time of this file, the license in use is the Microsoft Permissive License (Ms-PL) 
 *    * The license can be viewed at:
 *     * License.Txt in the root folder of this project
 *      * http://sobrietyengine.codeplex.com/license
 *       * http://www.microsoft.com/opensource/licenses.mspx
 *       
 *  </copyright>
 *   */

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SobrietyEngine.Actor;
using SobrietyEngine.Components;
using SobrietyEngine.Components.Common;
using SobrietyEngine.Components.Graphic;
using SobrietyEngine.Components.Misc;
using SobrietyEngine.Components.Paths;
using SobrietyEngine.Components.Physics;
using SobrietyEngine.Components.Physics.Movers;
using SobrietyEngine.Components.Physics.OnCollision;
using SobrietyEngine.Components.Trigger;
using SobrietyEngine.Components.Trigger.Response;
using SobrietyEngine.Guids;
using SobrietyEngine.PathFinding;
using SobrietyEngine.Scene;
using SobrietyEngine.Physics;


//THis is a kludge because all of this should be handled
//through actor actorDefinition files. This will be converted once the majority of the components have been
//finalized.
namespace SEGameExample.Kludge
{
    static class WorldMapSpawner
    {

        public static IActor CreateTriggerableText(IScene scene, String text, Vector2 pos, String triggerName, Boolean startVisible)
        {
            IActor actor = scene.CreateEmptyActor();

            actor.AttachComponent(new PositionCmp(pos));
            actor.AttachComponent(new DrawableText(text));
            ToggleVisibilityCmp tvc = new ToggleVisibilityCmp(new string[] { triggerName });
            actor.AttachComponent(tvc);

            actor.Initialize();

            if (startVisible == false)
                tvc.Trigger(CGuid.CreateEmpty());

            return actor;
        }

        public static List<IActor> CreateWorldMapNodes(IScene scene, Vector2[] nodes, String[] descriptions, Vector2 descPos, GraphicsDevice gd)//, String[] textureNames)
        {
            List<IActor> nodeActors = GameplaySpawner.createCirclePath(scene, nodes);

            //hackish, but we need to make all the edges on the circle path Bidirectional isntead of unidirectional
            foreach (IActor act in nodeActors)
            {
                PathNodeCmp pnc = act.Get<PathNodeCmp>();
                foreach (IEdge pathEdge in pnc.PathNode.Edges)
                    pathEdge.OneWay = false;
            }

            IComponent comp;
            List<IComponent> comps = new List<IComponent>();
            
            //add a debug texture to the path nodes, man, and descriptions
            int levelNum = 0;
            foreach (IActor actor in nodeActors)
            {
                levelNum++;
                String triggerName = "levelTrigger" + levelNum.ToString();

                //CreateDebugViews texture
                comp = new TexturedQuadCmp("Textures/PathNodeDbg");
                comps.Add(comp);

                //add a physics body component, used for the on collision event
                FarseerPhysicsCmp phys = new RectangleBodyCmp(scene.Name, new Vector2(0.1f,0.1f));
                comps.Add(phys);

                //create a trigger on each node                
                comp = new TriggerCmp(triggerName, true, false, 100, false);
                comps.Add(comp);

                //create the trigger on collission component
                comps.Add(new TriggerOnCollisionCmp());

                //lets make the node 'useable' so we can interact with it
                //comp = new UseableBase(0.05f);
                comp = new SEGameExample.Components.OnUse.OnUseEnterLevelCmp(triggerName);
                comps.Add(comp);

                //since these actors have already been initilized and registered onteh Scene, we
                //need to manually initilize and register the components. this process
                //needs to improve
                foreach (IComponent c in comps)
                {
                    actor.AttachComponent(c);
                    if (!c.InitComponent())
                    {
                        throw new Exception("Problem with WorldMapNodes init");
                    }
                    scene.RegisterComponent(c);
                }
                //get rid of this component list
                comps.Clear();

                //have to do physics body stuff after we init, so body is there
                //this will be true until each of these settings exist as vars in the component
                phys.Body.IsSensor = true;
                phys.Body.IgnoreGravity = true;

                //only have our physics bodies collide with 'movers' (circles that move actors about)
                phys.Body.CollisionCategories = CollisionCatagories.MoverTriggersAre;
                phys.Body.CollidesWith = CollisionCatagories.MoverTriggersHit;


                //create the text
                IActor textActor = CreateTriggerableText(scene, descriptions[levelNum - 1], descPos, triggerName, false);               
            }

            return nodeActors;
        }

        public static IActor CreatePlayer(IScene scene, CGuid user, IActor startingNode)
        {
            IActor actor = scene.CreateEmptyActor();

            actor.AttachComponent(new PositionCmp( startingNode.Get<IPosition>().PositionV3  ));
            actor.AttachComponent(new OrientationCmp());
            actor.AttachComponent(new TexturedQuadCmp("Textures/Missing"));

            //this path following was no good for world map, we need something we can control
            //with a controller based on PlayerOne input
            //actor.AttachComponent(new NextAtTargetAndEventCmp(startingNode.Guid, new RaiseLogEvent(new Jump(PlayerOne), PlayerOne), true));
            //so lets use a manual path following component
            
            
            //actor.AttachComponent(new PathFollowerCmp(startingNode.Guid));

            actor.AttachComponent(new LinearImpulseMovementCmp());
            actor.AttachComponent(new SEGameExample.Components.Controllers.WorldMapUser(user, startingNode.Guid));

            FarseerPhysicsCmp fpc = new CircleBodyCmp(scene.Name, 0.5f);
            actor.AttachComponent(fpc);
            
            
           
            actor.Initialize();

            fpc.IgnoreGravity = true;
            fpc.Body.CollisionCategories = CollisionCatagories.MoversAre;
            fpc.Body.CollidesWith = CollisionCatagories.MoversHit;

            return actor;
        }

        public static IActor CreateTimeLimitText(IScene scene, String text, Vector2 pos, float showForHowLong, Vector4 color)
        {
            IActor actor = scene.CreateEmptyActor();

            actor.AttachComponent(new PositionCmp(pos));
            actor.AttachComponent(new DrawableText(text, color));
            actor.AttachComponent(new TimeToLive(showForHowLong));

            actor.Initialize();

            return actor;
        }
    }
}
